package com.hzdesk.media.koreabatchmatvector.custom;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.view.View;

import com.hzdesk.media.koreabatchmatvector.bean.DcfBean;
import com.hzdesk.media.koreabatchmatvector.bean.PathBean;
import com.hzdesk.media.koreabatchmatvector.bean.SerPath;
import com.hzdesk.media.koreabatchmatvector.bean.SerPoint;
import com.hzdesk.media.koreabatchmatvector.config.AppConfig;
import com.hzdesk.media.koreabatchmatvector.contral.LineCtl;
import com.hzdesk.media.koreabatchmatvector.contral.OvaluCtl;
import com.hzdesk.media.koreabatchmatvector.contral.PenuCtl;
import com.hzdesk.media.koreabatchmatvector.contral.RectuCtl;
import com.hzdesk.media.koreabatchmatvector.inter.ISketchpadDraw;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author Mr.Lee
 */
public class DemoCanvas extends View {

    private static final String TAG = "DemoCanvas";
    private Canvas mCanvas;
    private Bitmap bitmap;
    private DcfBean mBean;
    private Paint mPaint;
    public Timer mTimer, pathTimer;
    private TimerTask playtask = null;
    private MyTimerTask myTimerTask = null;
    private long startTime;
    private long currentTime=0, length;
    private int number = 0;// 用户
    private int next;
    private int line_index;
    private float currentSX, currentSY, currentEX, currentEY;
    private ISketchpadDraw m_curTool;
    private SerPath mCurrentSerPath;
    private Path mCurrentPath;
    private boolean m_isTouchUp = false;
    private boolean stop = false;
    private List<TimerTask> mTimeList = new ArrayList<>();
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 11:
                    playDraw();
                    break;
                default:
                    break;
            }
        }
    };
    private MyHandler myHandler = new MyHandler();
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            currentTime ++;
        }
    };

    private List<DeskmediaCanvasUndoStack> mUndoStackList;

    public DemoCanvas(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();

    }

    public DemoCanvas(Context context) {
        super(context);
        initialize();

    }

    public DemoCanvas(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize();

    }

    private void initialize() {
        bitmap = Bitmap.createBitmap(AppConfig.SCREEN_WIDTH, AppConfig.SCREEN_HIGHR, Config.ARGB_8888);
        mCanvas = new Canvas();
        mCanvas.setBitmap(bitmap);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mUndoStackList = new ArrayList<>();
        mUndoStackList.add(new DeskmediaCanvasUndoStack());
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 1
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 2
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 3
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 4
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 5
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 6
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 7
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 8
        mUndoStackList.add(new DeskmediaCanvasUndoStack());// 9

    }

    public void startDraw(DcfBean bean) {
        startTime = new Date().getTime();
        this.mBean = bean;
        length = mBean.getLength();
        mTimer = new Timer();
        //mTimer.schedule(task, 0, 1);// 更新时间点
        pathTimer = new Timer();
        line_index = 0;
        StartTime();
        //Log.d(TAG, "size:" + mBean.getList().size());
    }

    public void stopDraw() {
        if (mTimer != null && pathTimer != null) {
            mTimer.cancel();
            pathTimer.cancel();
            mTimer.purge();
            pathTimer.purge();
            mTimer = null;
            pathTimer = null;
            Log.d(TAG, "-----over----"+length);
        }
    }

    public void pauseDraw() {
        stop = true;
        Log.d(TAG, "pauseDraw");
    }

    public void continueDraw() {
        stop = false;
        Log.d(TAG, "continueDraw");
    }

    public void changeProgress(long time){
        currentTime=time;

    }

    private void StartTime() {
        if (line_index < mBean.getList().size()) {
            myTimerTask = new MyTimerTask(myHandler, mBean.getList().get(line_index), line_index);
            if (myTimerTask != null) {
                mTimer.schedule(myTimerTask, 0, 1);
            }
        } else {
            stopDraw();
        }
    }
    /*
	 * @Override public void draw(Canvas canvas) {
	 * //canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR); //paint.setAlpha(0x40);
	 * canvas.drawBitmap(bitmap, 0, 0,mPaint);
	 * 
	 * }
	 */

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(bitmap, 0, 0, mPaint);
        super.onDraw(canvas);
        if (m_curTool != null) {
            if (!m_isTouchUp) { // 调用绘图功能
                m_curTool.draw(canvas);
            }
        }

    }

    public void undo(int num) {

        if (mUndoStackList.get(num).canUndo()) {
            int size = mUndoStackList.get(num).undoP.size();
            Pair<Integer, Bean> pair = mUndoStackList.get(num).undoP.get(size - 1);
            mUndoStackList.get(9).redoP.add(pair);
            mUndoStackList.get(9).undoP.remove(pair);
            mUndoStackList.get(num).undo();
        }
        mUndoStackList.get(9).rePaint();


    }

    public void redo(int num) {

        if (mUndoStackList.get(num).canRedo()) {
            int size = mUndoStackList.get(num).redoP.size();
            Pair<Integer, Bean> pair = mUndoStackList.get(num).redoP.get(size - 1);
            mUndoStackList.get(9).redoP.remove(pair);
            mUndoStackList.get(9).undoP.add(pair);
            mUndoStackList.get(num).redo();
        }
        mUndoStackList.get(9).rePaint();


    }

    public void clear(int num) {

		/*
		 * savePathList.clear(); deletePathList.clear();
		 */

        if (num == 1) {
            for (int i = 0; i < mUndoStackList.size(); i++) {
                mUndoStackList.get(i).clearAll();
            }
        } else {

            for (Pair<Integer, Bean> pair : mUndoStackList.get(num).undoP) {
                mUndoStackList.get(9).undoP.remove(pair);
            }
            for (Pair<Integer, Bean> pair : mUndoStackList.get(num).redoP) {
                mUndoStackList.get(9).redoP.remove(pair);
            }
            mUndoStackList.get(num).clearAll();
            mUndoStackList.get(9).rePaint();
        }
        Log.d(TAG, "clear");
        invalidate();
    }

    class MyHandler extends Handler {
        private PathBean bean;
        private int i;

        @SuppressLint("WrongCall")
        @Override
        public void handleMessage(Message msg) {

            // Log.i("<>"+i, "4");
            super.handleMessage(msg);
            Bundle bundle = msg.getData();
            bean = (PathBean) bundle.getSerializable("bean");
            i = bundle.getInt("i");
            // mTimeList.get(i).cancel();
            // Log.i("<>"+i, "5");
            if (msg.arg1 == 1) {
                // Log.i("<>"+i, "6");
                // Log.i("<>"+i, bean.getColor()+"");

                if (bean.getType().equals(AppConfig.PAINT_CLEAR)) {
                    clear(bean.getNumber());
                    //Log.e(TAG, "clear");
                    nextPath();
                }
                if (bean.getType().equals(AppConfig.PAINT_UNDO)) {
                    undo(bean.getNumber());
                    //Log.e(TAG, "undo");
                    nextPath();
                }
                if (bean.getType().equals(AppConfig.PAINT_REDO)) {
                    redo(bean.getNumber());
                    //Log.e(TAG, "redo");
                    nextPath();
                }

                if (bean.getType().equals(AppConfig.PAINT_RECT)) {
                    mCurrentSerPath = bean.getmSerPath();
                    getPaint(bean.getColor(), bean.getSize());
                    //Log.d(TAG, "PAINT_RECT");
                    m_curTool = new RectuCtl(mPaint);
                    mCurrentPath = getRectuPath(bean.getmSerPath());
                    perforPathTimer();
                    savePath(mCurrentPath,bean.getNumber(),bean.getColor(),bean.getSize());

                }
                if (bean.getType().equals(AppConfig.PAINT_OVAL)) {
                    mCurrentSerPath = bean.getmSerPath();
                    getPaint(bean.getColor(), bean.getSize());
                    //Log.d(TAG, "PAINT_OVAL");
                    m_curTool = new OvaluCtl(mPaint);
                    mCurrentPath = getOvaluPath(bean.getmSerPath());
                    perforPathTimer();
                    savePath(mCurrentPath,bean.getNumber(),bean.getColor(),bean.getSize());
                }
                if (bean.getType().equals(AppConfig.PAINT_LINE)) {
                    mCurrentSerPath = bean.getmSerPath();
                    getPaint(bean.getColor(), bean.getSize());
                    //Log.d(TAG, "PAINT_LINE");
                    m_curTool = new LineCtl(mPaint);
                    mCurrentPath = getLinePath(bean.getmSerPath());
                    perforPathTimer();
                    savePath(mCurrentPath,bean.getNumber(),bean.getColor(),bean.getSize());
                }

                if (bean.getType().equals(AppConfig.PAINT_PENU)) {
                    mCurrentSerPath = bean.getmSerPath();
                    getPaint(bean.getColor(), bean.getSize());
                    //Log.d(TAG, "PAINT_PENU");
                    m_curTool = new PenuCtl(mPaint);
                    mCurrentPath = getPenuPath(bean.getmSerPath());
                    perforPathTimer();// after Initialization paint and SerPath
                    savePath(mCurrentPath,bean.getNumber(),bean.getColor(),bean.getSize());
                }

            }

        }
    }

    private void getPaint(String color, int size) {
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.parseColor("#" + color));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(size);

    }

    private Path getPenuPath(SerPath serPath) {
        Path path = new Path();
        int i = serPath.mPoints.size();
        if (i < 3) {
            return path;
        }
        SerPoint point = serPath.mPoints.get(0);
        path.moveTo(point.x, point.y);
        path.lineTo(point.x, point.y);
        float mX = point.x;
        float mY = point.y;
        for (int j = 1; j < serPath.mPoints.size() - 1; j++) {
            SerPoint point2 = serPath.mPoints.get(j);
            path.quadTo(mX, mY, (point2.x + mX) / 2, (point2.y + mY) / 2);
            path.lineTo(point2.x, point2.y);
            mX = point2.x;
            mY = point2.y;
        }
        SerPoint point2 = serPath.mPoints.get(i - 1);
        path.lineTo(point2.x, point2.y);
        mX = point2.x;
        mY = point2.y;
        return path;
    }

    private Path getLinePath(SerPath serPath) {
        Path path = new Path();
        int size = serPath.mPoints.size();
        SerPoint point = serPath.mPoints.get(0);
        SerPoint point2 = serPath.mPoints.get(size - 1);
        path.moveTo(point.x, point.y);
        path.lineTo(point2.x, point2.y);
        return path;
    }

    private Path getOvaluPath(SerPath serPath) {
        RectF rectf = new RectF();
        int size = serPath.mPoints.size();
        rectf.left = serPath.mPoints.get(0).x;
        rectf.top = serPath.mPoints.get(0).y;
        rectf.right = serPath.mPoints.get(size - 1).x;
        rectf.bottom = serPath.mPoints.get(size - 1).y;
        Path path = new Path();
        path.addOval(rectf, Path.Direction.CW);
        return path;
    }

    private Path getRectuPath(SerPath serPath) {
        int size = serPath.mPoints.size();
        Path path = new Path();
        path.addRect(serPath.mPoints.get(0).x, serPath.mPoints.get(0).y, serPath.mPoints.get(size - 1).x,
                serPath.mPoints.get(size - 1).y, Path.Direction.CW);
        return path;
    }

    private void savePath(Path path, int num,String color,int size) {
        number += 1;
        Bean bean=new Bean(path,color,size);
        Log.d(TAG, bean.getColor());
        mUndoStackList.get(num).push(bean, number);
        mUndoStackList.get(9).push(bean, number);
    }

    private void playDraw() {
        if (next < mCurrentSerPath.mPoints.size()) {
            float x = mCurrentSerPath.mPoints.get(next).x;
            float y = mCurrentSerPath.mPoints.get(next).y;
            // Log.d(TAG, "playDraw>>:"+line_index+"|"+next);
            if (next == (mCurrentSerPath.mPoints.size() - 1)) {
                touchUp(x, y);
            } else {
                touchMove(x, y);
            }
            invalidate();
        }
        // Log.d(TAG, "next:"+next);

    }


    private void perforPathTimer() {
        if (mCurrentSerPath.mPoints.size() < 0) {
            drawPath();
        } else {
            m_isTouchUp = false;
            if (next == 0) {
                touchDown();
            }
            next++;
            playtask = new TimerTask() {
                @Override
                public void run() {
                    Message message = new Message();
                    message.what = 11;
                    handler.sendMessage(message);
                }
            };
            if (playtask != null) {
                if (next < mCurrentSerPath.mTimes.size()) {
                    pathTimer.schedule(playtask, mCurrentSerPath.mTimes.get(next) - mCurrentSerPath.mTimes.get(next - 1));
                } else {
                    playtask.cancel();
                }
            }
        }

    }

    private void nextPath() {
        line_index++;
        next = 0;
        StartTime();
    }

    private void touchDown() {
        currentSX = mCurrentSerPath.mPoints.get(0).x;
        currentSY = mCurrentSerPath.mPoints.get(0).y;
        m_curTool.touchDown(currentSX, currentSY);
    }

    private void touchMove(float x, float y) {
        m_curTool.touchMove(x, y);
        currentSX = x;
        currentSY = y;
        // performTimer();
        perforPathTimer();
        //Log.d(TAG, "move:" + next);
    }

    private void touchUp(float x, float y) {
        m_isTouchUp = true;
        m_curTool.touchUp(x, y);
        m_curTool.draw(mCanvas);
        Log.d(TAG, "draw");
        nextPath();
    }

    private void drawPath() {
        mCanvas.drawPath(mCurrentPath, mPaint);
        invalidate();
        nextPath();
    }

    class MyTimerTask extends TimerTask {
        private long time;
        private MyHandler handler;
        private PathBean bean;
        private int i;

        public MyTimerTask(MyHandler handler, PathBean bean, int i) {
            this.time = bean.getTime();
            this.handler = handler;
            this.bean = bean;
            this.i = i;
        }

        @Override
        public void run() {
            Message message = new Message();
            if (!stop) {
                if (currentTime >= time) {
                    message.arg1 = 1;
                    Bundle bundle = new Bundle();
                    bundle.putSerializable("bean", bean);
                    //Log.d(TAG, "i:" + i);
                    bundle.putInt("i", i);
                    message.setData(bundle);
                    handler.sendMessage(message);
                    myTimerTask.cancel();
                }

            } else {
                try {
                    startTime = startTime + 1;
                    //Log.d(TAG, startTime+"");
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }


        }

    }

    class DeskmediaCanvasUndoStack {
        private ArrayList<Pair<Integer, Bean>> undoP = new ArrayList<>();
        private ArrayList<Pair<Integer, Bean>> redoP = new ArrayList<>();
        private ArrayList<Pair<Integer, Bean>> removesP = new ArrayList<>();

        public DeskmediaCanvasUndoStack() {
            // TODO Auto-generated constructor stub
        }

        public void push(Bean bean, int i) {
            undoP.add(new Pair(i, bean));
        }

        public void clearAll() {
            undoP.clear();
            redoP.clear();
            removesP.clear();
            Paint paint = new Paint();
            paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
            mCanvas.drawPaint(paint);
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
            invalidate();
        }

        public void undo() {
            if (canUndo()) {
                Pair<Integer, Bean> pair = undoP.get(undoP.size() - 1);
                redoP.add(pair);
                undoP.remove(pair);
                invalidate();
            }
        }

        public void redo() {

            if (canRedo()) {
                Pair<Integer, Bean> pair = redoP.get(redoP.size() - 1);
                undoP.add(pair);
                redoP.remove(redoP.size() - 1);
                invalidate();
            }

        }

        public void rePaint() {
            Paint paint = new Paint();
            paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
            mCanvas.drawPaint(paint);
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC));

            Collections.sort(undoP, new Comparator<Pair<Integer, Bean>>() {
                @Override
                public int compare(Pair<Integer, Bean> p1, Pair<Integer, Bean> p2) {
                    return p1.first - p2.first;
                }
            });
            for (int i = 0; i < undoP.size(); i++) {
                Pair<Integer, Bean> pair = undoP.get(i);
                Bean bean = pair.second;
                mCanvas.drawPath(bean.getPath(), getPaint(bean.getColor(),bean.getSize()));
            }
            invalidate();

        }
        public Paint getPaint(String color,int size){
            Paint paint=new Paint();
            paint.setAntiAlias(true);
            paint.setDither(true);
            paint.setColor(Color.parseColor("#" + color));
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeCap(Paint.Cap.ROUND);
            paint.setStrokeWidth(size);
            return paint;

        }

        public boolean canUndo() {
            return (undoP.size() > 0);
        }

        public boolean canRedo() {
            return (redoP.size() > 0);
        }
    }

    class Bean {
        private Path path;
        private String color;
        private int size;

        public Bean(Path path, String color, int size) {
            this.path = path;
            this.color = color;
            this.size = size;
        }

        public Path getPath() {
            return path;
        }

        public void setPath(Path path) {
            this.path = path;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }
    }

}
